package easycloud.ecs.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventObject;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.filechooser.FileFilter;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdesktop.application.Action;
import org.jdesktop.application.Application;
import org.jdesktop.application.LocalStorage;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;

import com.google.common.collect.Multimap;

import easycloud.ecs.App;
import easycloud.ecs.api.IProvider;
import easycloud.ecs.config.ConfigException;
import easycloud.ecs.config.MonitorConfig;
import easycloud.ecs.config.MonitorConfigUtils;
import easycloud.ecs.config.ProviderConfig;
import easycloud.ecs.config.ProviderConfigUtils;

public class MainFrame extends SingleFrameApplication {

	private static final Log logger = LogFactory.getLog(MainFrame.class);

	private ResourceMap resource;

	private LocalStorage storage;

	private JTable syncTable;

	private JTable providerTable;

	private JList consoleList;

	public void addConsoleMsg(String msg) {
		((ConsoleListModel) consoleList.getModel()).addElement(msg);
	}

	@Action(name = "About")
	public void aboutECS() {
		JOptionPane.showMessageDialog(getMainFrame(),
				"Welcome to EasyCloudStorage", "About",
				JOptionPane.INFORMATION_MESSAGE);
	}

	@Override
	public void ready() {
		App.getInstance().setMainFrame(this);
	}

	@Action(name = "Add Sync Folder")
	public void addSyncFolder() {
		JFileChooser chooser = new JFileChooser("Add Sync Folder");
		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

		int result = chooser.showOpenDialog(getMainFrame());
		if (result == JFileChooser.APPROVE_OPTION) {
			File file = chooser.getSelectedFile();
			((SyncTableModel) syncTable.getModel()).addFolder(file);
		}
	}

	@Action(name = "Remove Sync Folder")
	public void removeSyncFolder() {

	}

	@Action(name = "Exit")
	public void exitECS() {
		if (JOptionPane.showConfirmDialog(getMainFrame(),
				"Do you really want to exit?") == JOptionPane.YES_OPTION) {
			this.exit();
		}
	}

	@Override
	protected void initialize(String[] args) {
		resource = getContext().getResourceManager().getResourceMap(
				MainFrame.class);
		storage = getContext().getLocalStorage();
	}

	@Action(name = "Open Config")
	public void openConfig() {
		JFileChooser chooser = new JFileChooser("Open Provider Config");
		chooser.setCurrentDirectory(new File("."));
		chooser.setMultiSelectionEnabled(true);
		chooser.setFileFilter(new FileFilter() {

			@Override
			public boolean accept(File f) {
				if (f.isDirectory()
						|| FilenameUtils.isExtension(f.getName(), "properties")) {
					return true;
				}
				return false;
			}

			@Override
			public String getDescription() {
				return "配置文件|(*.properties)";
			}

		});

		int result = chooser.showOpenDialog(getMainFrame());
		if (result == JFileChooser.APPROVE_OPTION) {
			File[] files = chooser.getSelectedFiles();
			List<ProviderConfig> providerConfigs = ProviderConfigUtils
					.getProviderConfigs(files);
			try {
				App.getInstance().getMonitorService()
						.loadProviderConfig(providerConfigs);
			} catch (ConfigException e) {
				JOptionPane.showMessageDialog(getMainFrame(),
						"Open Provider Config Exception: " + e.getMessage(),
						"Warning", JOptionPane.WARNING_MESSAGE);
			}
		}

		File dir = storage.getDirectory();
		File monitorConfigFile = new File(dir, "monitor.json");
		try {
			if (!monitorConfigFile.exists()) {
				monitorConfigFile.createNewFile();
				MonitorConfig sampleConfig = new MonitorConfig();
				MonitorConfigUtils.writeConfig(sampleConfig, monitorConfigFile);
			}
			MonitorConfig monitorConfig = MonitorConfigUtils
					.readConfig(monitorConfigFile);
			App.getInstance().getMonitorService()
					.loadMonitorConfig(monitorConfig);
			Map<String, IProvider> providers = App.getInstance()
					.getMonitorService().getProviders();
			
			((SyncTableModel) syncTable.getModel()).setTableHeader(providers
					.values());
			((SyncTableModel) syncTable.getModel()).setTableContent(App
					.getInstance().getMonitorService().getSyncDirs());

			Map<IProvider, Map<String, String>> eTags = MonitorConfigUtils
					.readETags(providers, dir);
			App.getInstance().getETagService().loadETags(eTags);

			MonitorConfigUtils.readStatistics(providers, dir);
			((ProviderTableModel) providerTable.getModel())
					.setTableContent(providers);
			addConsoleMsg("Init Finished");
		} catch (ConfigException e) {
			JOptionPane.showMessageDialog(getMainFrame(),
					"Open Monitor Config Exception: " + e.getMessage(),
					"Warning", JOptionPane.WARNING_MESSAGE);
		} catch (IOException e) {
			JOptionPane.showMessageDialog(getMainFrame(),
					"Create Monitor Config Exception: " + e.getMessage(),
					"Warning", JOptionPane.WARNING_MESSAGE);
		}

	}

	private void saveMonitorConfig() {
		MonitorConfig config = new MonitorConfig();
		Multimap<File, IProvider> syncDirs = App.getInstance()
				.getMonitorService().getSyncDirs();
		for (Entry<File, Collection<IProvider>> entry : syncDirs.asMap()
				.entrySet()) {
			List<String> providerNames = new ArrayList<String>();
			for (IProvider provider : entry.getValue()) {
				providerNames.add(provider.getName());
			}
			config.getSyncDirs().put(entry.getKey().getAbsolutePath(),
					providerNames);
		}
		File dir = storage.getDirectory();
		try {
			MonitorConfigUtils.writeConfig(config, dir);
			Map<IProvider, Map<String, String>> eTags = App.getInstance()
					.getETagService().getETags();
			MonitorConfigUtils.writeETags(eTags, dir);
			MonitorConfigUtils.writeProviderStatistics(syncDirs.values(), dir);
		} catch (ConfigException e) {
			e.printStackTrace();
		}

	}

	@Override
	protected void shutdown() {
		App.getInstance().getMonitorService().stop();
		saveMonitorConfig();
		super.shutdown();
	}

	@Action(name = "Start Sync")
	public void startSync() {
		App.getInstance().getMonitorService().start();
	}

	@Override
	protected void startup() {
		getMainFrame().setTitle(
				resource.getString(Application.KEY_APPLICATION_TITLE));

		// Menubar
		JMenuBar menuBar = new JMenuBar();
		JMenu fileMenu = new JMenu("File");
		menuBar.add(fileMenu);
		JMenuItem openConfigMenuItem = new JMenuItem();
		openConfigMenuItem.setAction(getContext().getActionMap(this).get(
				"Open Config"));
		JMenuItem exitMenuItem = new JMenuItem();
		exitMenuItem.setAction(getContext().getActionMap(this).get("Exit"));
		fileMenu.add(openConfigMenuItem);
		fileMenu.addSeparator();
		fileMenu.add(exitMenuItem);

		JMenu syncMenu = new JMenu("Sync");
		menuBar.add(syncMenu);
		JMenuItem startSyncMenuItem = new JMenuItem();
		startSyncMenuItem.setAction(getContext().getActionMap(this).get(
				"Start Sync"));
		JMenuItem stopSyncMenuItem = new JMenuItem();
		stopSyncMenuItem.setAction(getContext().getActionMap(this).get(
				"Stop Sync"));
		JMenuItem addSyncMenuItem = new JMenuItem();
		addSyncMenuItem.setAction(getContext().getActionMap(this).get(
				"Add Sync Folder"));
		JMenuItem removeSyncMenuItem = new JMenuItem();
		removeSyncMenuItem.setAction(getContext().getActionMap(this).get(
				"Remove Sync Folder"));
		syncMenu.add(startSyncMenuItem);
		syncMenu.add(stopSyncMenuItem);
		syncMenu.addSeparator();
		syncMenu.add(addSyncMenuItem);
		syncMenu.add(removeSyncMenuItem);

		JMenu helpMenu = new JMenu("Help");
		menuBar.add(helpMenu);
		JMenuItem aboutMenuItem = new JMenuItem();
		aboutMenuItem.setAction(getContext().getActionMap(this).get("About"));
		helpMenu.add(aboutMenuItem);

		getMainFrame().setJMenuBar(menuBar);

		// Panel
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		syncTable = new JTable(new SyncTableModel());
		providerTable = new JTable(new ProviderTableModel());
		consoleList = new JList(new ConsoleListModel());

		JScrollPane northPanel = new JScrollPane(syncTable);
		northPanel.setPreferredSize(new Dimension(600, 150));
		JScrollPane centerPanel = new JScrollPane(providerTable);
		centerPanel.setPreferredSize(new Dimension(600, 150));
		JScrollPane southPanel = new JScrollPane(consoleList);
		southPanel.setPreferredSize(new Dimension(600, 150));
		panel.add(northPanel, BorderLayout.NORTH);
		panel.add(centerPanel, BorderLayout.CENTER);
		panel.add(southPanel, BorderLayout.SOUTH);

		addExitListener(new ExitListener() {
			@Override
			public boolean canExit(EventObject e) {
				if (e != null) {
					boolean bOkToExit = false;
					Component source = (Component) e.getSource();
					bOkToExit = JOptionPane.showConfirmDialog(source,
							"Do you really want to exit?") == JOptionPane.YES_OPTION;
					return bOkToExit;
				} else {
					return true;
				}
			}

			@Override
			public void willExit(EventObject event) {

			}

		});

		getMainFrame().setSize(640, 640);
		this.show(panel);
	}

	@Action(name = "Stop Sync")
	public void stopSync() {
		App.getInstance().getMonitorService().stop();
	}
}
